package helper.scxml.scxml2.zone.t2

import helper.base.A2LHM
import helper.base.LHMHelper.A2LHMExpand.add
import helper.base.LHMHelper.A2LHMExpand.makeA2LHM
import helper.base.LHMHelper.A3LHM
import helper.base.LHMHelper.A3LHM.Companion.makeA3LHM
import helper.base.StringHelper.removeEmptyLine
import helper.base.string.ToLStringHelper.IToL1String
import helper.base.string.ToLStringHelper.IToL2String
import helper.base.string.ToStrHelper.IToStr
import helper.base.string.ToStrHelper.TabStringUnit.Companion.makeTabStringUnit
import helper.scxml.scxml2.zone.t2.ConfigHelper.Config
import helper.scxml.scxml2.zone.t2.case3_factoryLines.FLEnvHelper
import helper.scxml.strategy.StrategyHelper.TimedEventHelper.TimedEvent
import helper.scxml.strategy.StrategyHelper.TimedEventHelper.TimedEvent.Expand.getCombinedProductMap
import helper.scxml.strategy.TotalStrategyHelper.ISNode
import helper.scxml.strategy.sNodeUnit.SNodeUnitHelper.ISNodeUnit
import helper.scxml.strategy.sNodeUnit.T2SNodeUnitHelper
import helper.scxml.strategy.sNodeUnit.T2SNodeUnitHelper.ERT2SNodeUnit
import helper.scxml.strategy.sNodeUnit.T2SNodeUnitHelper.ERT2SNodeUnit.Companion.makeERT2SNodeUnit
import helper.scxml.strategy.sNodeUnit.T2SNodeUnitHelper.SubT2SNodeUnit
import helper.scxml.strategy.sNodeUnit.T2SNodeUnitHelper.T2SNodeUnit

// T3SNodeUnitHelper 对象包含用于处理第三类型的策略节点单元的辅助类和方法
object T3SNodeUnitHelper {
    // T3SNodeUnit 类表示第三类型的策略节点单元
    open class T3SNodeUnit : ISNodeUnit, IToStr, IToL1String, IToL2String {
        // funLHM 存储了从状态节点到处理区域状态并返回字符串集合的函数的映射
        val funLHM: A2LHM<ISNode?, (Config) -> LinkedHashSet<String>> = makeA2LHM()

        // relationLHM 存储了状态节点之间的关系，即从一个节点通过字符串标识符到另一个节点的映射
        val relationLHM: A3LHM<ISNode?, String, ISNode> = makeA3LHM()

        companion object {
            // 静态工厂方法创建 T3SNodeUnit 实例
            fun makeT3SNodeUnit() = T3SNodeUnit()
        }

        /**
         * 根据给定的区域状态，找出所有叶子节点。
         *
         * 叶子节点定义为没有进一步转换关系的状态节点，这通常意味着它们是策略执行的最终状态。
         *
         * @param config 当前的区域状态，用于确定哪些节点是叶子节点。
         * @return 一个包含所有叶子节点的 LinkedHashSet 集合。
         */
        fun getLeafs(config: Config): LinkedHashSet<T2SNodeUnit> {
            // 辅助函数，判断一个节点是否为叶子节点
            fun ISNode?.isLeaf(): Boolean {
                return relationLHM[this].isNullOrEmpty() // 返回节点的叶子状态
            }

            // 当前正在处理的节点集合，初始化包含一个空节点表示起始状态
            var nowSNodes = linkedSetOf<ISNode?>(null)
            // 用于存储找到的叶子节点
            val res: LinkedHashSet<T2SNodeUnit> = linkedSetOf()

            // 循环处理直到没有更多节点需要处理
            while (nowSNodes.isNotEmpty()) {
                // 存储新一轮处理中发现的节点
                val newSNodes = linkedSetOf<ISNode?>()
                nowSNodes.forEach { node ->
                    if (node.isLeaf()) { // 如果当前节点是叶子节点，则添加到结果集
                        require(node is T2SNodeUnit) // 确保所有叶子节点都是 T2SNodeUnit 类型
                        res.add(node)
                    } else { // 否则，根据当前区域状态查找下一步的节点
                        funLHM[node]!!(config).forEach { str ->
                            relationLHM[node, str]?.let {
                                newSNodes.add(it) // 将找到的新节点添加到待处理集合中
                            }
                        }
                    }
                }
                nowSNodes = newSNodes // 更新待处理节点集合为新发现的节点
            }
            return res // 返回所有找到的叶子节点
        }

        // 获取与给定区域状态相关的所有时间事件选择列表
        override fun getMsTimeEventChoiceList(config: Config): ArrayList<TimedEvent> {
            val res = arrayListOf<TimedEvent>()
            getLeafs(config).forEach {
                it.getMTimeEventChoice(config)?.let {
                    res.add(it)
                }
            }
            return res
        }

        // 获取与给定区域状态相关的所有时间事件选择及其权重的映射
        override fun getMsTimeEventChoiceWeightLHM(config: Config): A2LHM<List<TimedEvent>, Double> {
            val leafs = getLeafs(config)
            val t1 = leafs.map {
                it.getMTimeEventChoiceWeightLHM(config)
            }
            return t1.getCombinedProductMap()
        }

        // 生成 T3SNodeUnit 的字符串表示
        override fun toStr(tabNum: Int): String {
            val sb = StringBuilder()
            val tsu = makeTabStringUnit(tabNum)
            sb.append("${tsu.tabNumStr0}${javaClass.simpleName}(")
            sb.append("funLHM: A2LHM<ISNode?, (ZoneState) -> LinkedHashSet<String>>,relationLHM=\n")
            relationLHM.touch { a1, a2, a3 ->
                sb.append("${tsu.tabNumStr1}${a1}_${a2}_${a3.toStr(tsu.tabNum1).trim()}\n")
            }
            sb.append("${tsu.tabNumStr0})\n")
            return sb.toString().removeEmptyLine()
        }
    }

    // 总策略
    class ERT3SNodeUnit(
        val aMsERT2SNodeUnitLHM: A2LHM<String, ERT2SNodeUnit> = makeA2LHM()
    ) : T3SNodeUnit() {
        companion object {
            fun makeERT3SNodeUnit(
                aMsERT2SNodeUnitLHM: A2LHM<String, ERT2SNodeUnit>,
            ): ERT3SNodeUnit {
                return ERT3SNodeUnit(aMsERT2SNodeUnitLHM).apply {
                    val devs = aMsERT2SNodeUnitLHM.keys.toList()
                    funLHM.add(null) { _: Config ->
                        LinkedHashSet(devs)
                    }
                    aMsERT2SNodeUnitLHM.forEach { (t, u) ->
                        relationLHM.add(null, t, u)
                    }
                }
            }

            fun makeERT3SNodeUnit(
                names: List<String>,
                aStringRenStrategyLHM: A2LHM<String, SubT2SNodeUnit>,
                aStringEnvStrategyLHM: A2LHM<String, SubT2SNodeUnit>,
            ): ERT3SNodeUnit {
                val aMsERT2SNodeUnitLHM: A2LHM<String, ERT2SNodeUnit> = makeA2LHM()
                names.forEach {
                    aMsERT2SNodeUnitLHM.add(
                        it,
                        makeERT2SNodeUnit(
                            env = aStringEnvStrategyLHM[it]!!,
                            ren = aStringRenStrategyLHM[it]!!,
                        ),
                    )
                }
                return makeERT3SNodeUnit(aMsERT2SNodeUnitLHM)
            }
        }
    }
}